<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  
  <title>Fragment弃坑之旅 | 清风向阳</title>
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  
    <meta name="keywords" content="Joker,Joker's Blog" />
  
  <meta name="description" content="Fragment至诞生之日起，就开始饱受争议，很多人都认为Fragment的设计不合理，并提倡放弃Fragment，这种现象产生的原因我觉得大概就是使用了Fragment之后出现了很多Crash，而且这个Bug都似乎不是太能理解，导致不能很好的去解决。当然任何事物都是有两面性，存在即合理，Fragment肯定也是有其使用价值的。">
<meta name="keywords" content="Fragment,android">
<meta property="og:type" content="article">
<meta property="og:title" content="Fragment弃坑之旅">
<meta property="og:url" content="http://mjjde.github.io/2017/04/26/Fragment弃坑之旅/index.html">
<meta property="og:site_name" content="清风向阳">
<meta property="og:description" content="Fragment至诞生之日起，就开始饱受争议，很多人都认为Fragment的设计不合理，并提倡放弃Fragment，这种现象产生的原因我觉得大概就是使用了Fragment之后出现了很多Crash，而且这个Bug都似乎不是太能理解，导致不能很好的去解决。当然任何事物都是有两面性，存在即合理，Fragment肯定也是有其使用价值的。">
<meta property="og:image" content="http://jokero1o.github.io/images/blog_fragment.jpg">
<meta property="og:updated_time" content="2017-09-15T07:00:31.000Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Fragment弃坑之旅">
<meta name="twitter:description" content="Fragment至诞生之日起，就开始饱受争议，很多人都认为Fragment的设计不合理，并提倡放弃Fragment，这种现象产生的原因我觉得大概就是使用了Fragment之后出现了很多Crash，而且这个Bug都似乎不是太能理解，导致不能很好的去解决。当然任何事物都是有两面性，存在即合理，Fragment肯定也是有其使用价值的。">
<meta name="twitter:image" content="http://jokero1o.github.io/images/blog_fragment.jpg">
  
  
    <link rel="icon" href="/favicon_pic.ico">
  
  <link href="//cdn.bootcss.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" type="text/css">
  <link rel="stylesheet" href="/css/style.css">
  <script src="/js/pace.min.js"></script>
  

  
  

</head>

<body>
  <div id="container">
      <header id="header">
    <div id="banner"></div>
    <div id="header-outer">
        <div id="header-menu" class="header-menu-pos animated">
            <div class="header-menu-container">
                <a href="/" class="left">
                    <span class="site-title">Joker&#39;s Blog</span>
                </a>
                <nav id="header-menu-nav" class="right">
                    
                    <a  href="/">
                        <i class="fa fa-home"></i>
                        <span>Home</span>
                    </a>
                    
                    <a  href="/archives">
                        <i class="fa fa-archive"></i>
                        <span>Archives</span>
                    </a>
                    
                    <a  href="/about">
                        <i class="fa fa-user"></i>
                        <span>About</span>
                    </a>
                    
                </nav>
                <a class="mobile-header-menu-button">
                    <i class="fa fa-bars"></i>
                </a>
            </div>
        </div>
        <div id="header-row">
            <div id="logo">
                <a href="/">
                    <img src="/images/avatar.jpg" alt="logo">
                </a>
            </div>
            <div class="header-info">
                <div id="header-title">
                    
                    <h2>
                        Joker&#39;s Blog
                    </h2>
                    
                </div>
                <div id="header-description">
                    
                    <h3>
                        一个认真的技术博客
                    </h3>
                    
                </div>
            </div>
            <nav class="header-nav">
                <div class="social">
                    
                        <a title="Joker"  href="//joker-studio.pub">
                            <i class="fa fa-home fa-2x"></i></a>
                    
                        <a title="Github" target="_blank" href="//github.com/mjjde">
                            <i class="fa fa-github fa-2x"></i></a>
                    
                </div>
            </nav>
        </div>
    </div>
</header>
      <div class="outer">
        <section id="main" class="body-wrap"><article id="post-Fragment弃坑之旅" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-inner">
    
      <header class="article-header">
        
  
    <h1 class="post-title" itemprop="name">
      Fragment弃坑之旅
    </h1>
    <div class="post-title-bar">
      <ul>
          
              <li>
                  <i class="fa fa-book"></i>
                  
                      <a href="/categories/Android技术/">Android技术</a>
                  
              </li>
          
        <li>
          <i class="fa fa-calendar"></i>  2017-04-26
        </li>
        <li>
          <i class="fa fa-eye"></i>
          <span id="busuanzi_value_page_pv"></span>
        </li>
      </ul>
    </div>
  

          
      </header>
    
    <div class="article-entry post-content" itemprop="articleBody">
      
            
            <blockquote>
<p>Fragment至诞生之日起，就开始饱受争议，很多人都认为Fragment的设计不合理，并提倡放弃Fragment，这种现象产生的原因我觉得大概就是使用了Fragment之后出现了很多Crash，而且这个Bug都似乎不是太能理解，导致不能很好的去解决。当然任何事物都是有两面性，存在即合理，Fragment肯定也是有其使用价值的。<br><a id="more"></a><br><img src="http://jokero1o.github.io/images/blog_fragment.jpg" alt=""></p>
</blockquote>
<p>由于在使用Fragment的过程中会产生莫名其妙的Crash，这类Crash很隐蔽，一不小心就会出现等特点。我们来总结下具体的Crash来在开发中保证Fragment开发的稳定性，减少Crash的发生率。</p>
<h2 id="getActivity-方法报NPE"><a href="#getActivity-方法报NPE" class="headerlink" title="getActivity()方法报NPE"></a><a href="#getActivity_28_29_u65B9_u6CD5_u62A5NPE" title="getActivity()方法报NPE"></a>getActivity()方法报NPE</h2><p>一般在应用正常使用这个API时是没有任何问题的,而且在测试的过程中也很难出现，但是在App上线后时不时的就会有这样的Crash产生，那就很奇怪了，也是个头疼的问题，而且这类错误不容易复现，那么这势必会让程序员给Fragment减分。那么我们来看下这个API是怎么调用的。</p>
<figure class="highlight aspectj"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">final</span> <span class="keyword">public</span> <span class="function">FragmentActivity <span class="title">getActivity</span><span class="params">()</span> </span>&#123;</div><div class="line">    <span class="keyword">return</span> mHost == <span class="keyword">null</span> ? <span class="keyword">null</span> : (FragmentActivity) mHost.getActivity();</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>mHost是Fragment绑定的宿主Activity，那么当这个方法返回为Null,可以看到其实是这个变量mHost为Null。<br>我们来看下这个值是从何而来的，那么又在什么时候失去的。我们将查看源码来解决这个问题。</p>
<figure class="highlight haxe"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">xxxFragment = XXXFragment.<span class="keyword">new</span><span class="type">Instance</span>(<span class="literal">null</span>);</div><div class="line">getFragmentManager()</div><div class="line">    .beginTransaction()</div><div class="line">    .replace(R.id.container,xxxFragment)</div><div class="line">    .commit();</div></pre></td></tr></table></figure>
<p>上面的代码是我们将一个Fragment加入到Activity的常用手段。那么Fragment的神奇的生命之旅也开始了。我们主要是找到mHost这个变量是如果产生和消失的，并不打算详细的介绍Fragment的每个生命周期的动作。我们在Fragment源码中并没有找到mHost的赋值过程，那么mHost的赋值肯定是从下面的一段代码开始的了。</p>
<figure class="highlight aspectj"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="function">FragmentManager <span class="title">getFragmentManager</span><span class="params">()</span> </span>&#123;</div><div class="line">    <span class="function"><span class="keyword">return</span> mFragments.<span class="title">getFragmentManager</span><span class="params">()</span></span>;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>我们在Activity中找到如上代码，那么mFragments又是什么，在哪里实例化的呢。</p>
<figure class="highlight actionscript"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">final</span> FragmentController mFragments = FragmentController.createController(<span class="keyword">new</span> HostCallbacks());</div></pre></td></tr></table></figure>
<p>原来mFragments是FragmentController实例变量，在Activity初始化的时候就开始实例化的了。好的，我们来看下这段代码。</p>
<figure class="highlight aspectj"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//隐藏了构造函数</span></div><div class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="function">FragmentController <span class="title">createController</span><span class="params">(FragmentHostCallback&lt;?&gt; callbacks)</span> </span>&#123;</div><div class="line">    <span class="keyword">return</span> <span class="keyword">new</span> FragmentController(callbacks);</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">private</span> <span class="title">FragmentController</span><span class="params">(FragmentHostCallback&lt;?&gt; callbacks)</span> </span>&#123;</div><div class="line">    mHost = callbacks;</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="comment">//调用父类的构造</span></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="title">HostCallbacks</span><span class="params">()</span> </span>&#123;</div><div class="line">    <span class="keyword">super</span>(Activity.<span class="keyword">this</span> <span class="comment">/*activity*/</span>);</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="comment">//父类构造</span></div><div class="line">FragmentHostCallback(Activity activity, Context context, Handler <span class="keyword">handler</span>,</div><div class="line">    <span class="keyword">int</span> windowAnimations) &#123;</div><div class="line">    mActivity = activity;</div><div class="line">    mContext = context;</div><div class="line">    mHandler = <span class="keyword">handler</span>;</div><div class="line">    mWindowAnimations = windowAnimations;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>我们可以看到HostCallbacks包含了Activity的引用,并且传给了FragmentHostCallback,FragmentController在构造函数里持有了FragmentHostCallback对象。这样的话FragmentController就可以操作mHost来操作FragmentHostCallback中的FragmentManagerImpl对象了。getFragmentManager()也就拿到了FragmentManagerImpl对象的引用。我们再来看下beginTransaction()方法。<br>//FragmentManagerImpl.java<br>//返回了一个BackStackRecord,同是有把自己作为参数传了过去<br>//BackStackRecord的mManager持有了FragmentManagerImpl的引用<br>public FragmentTransaction beginTransaction() {<br>return new BackStackRecord(this);<br>}</p>
<p>接下来我们来看下BackStackRecord的replace方法:</p>
<figure class="highlight aspectj"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="function">FragmentTransaction <span class="title">replace</span><span class="params">(<span class="keyword">int</span> containerViewId, Fragment fragment)</span> </span>&#123;</div><div class="line">        <span class="function"><span class="keyword">return</span> <span class="title">replace</span><span class="params">(containerViewId, fragment, <span class="keyword">null</span>)</span></span>;</div><div class="line">    &#125;</div><div class="line"></div><div class="line"><span class="keyword">public</span> <span class="function">FragmentTransaction <span class="title">replace</span><span class="params">(<span class="keyword">int</span> containerViewId, Fragment fragment, String tag)</span> </span>&#123;</div><div class="line">        <span class="keyword">if</span> (containerViewId == <span class="number">0</span>) &#123;</div><div class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException(<span class="string">"Must use non-zero containerViewId"</span>);</div><div class="line">        &#125;</div><div class="line"></div><div class="line">        doAddOp(containerViewId, fragment, tag, OP_REPLACE);</div><div class="line">        <span class="keyword">return</span> <span class="keyword">this</span>;</div><div class="line">&#125;</div><div class="line"></div><div class="line">将FragmentManagerImpl的引用传给xxxFragment</div><div class="line"><span class="keyword">private</span> <span class="function"><span class="keyword">void</span> <span class="title">doAddOp</span><span class="params">(<span class="keyword">int</span> containerViewId, Fragment fragment, String tag, <span class="keyword">int</span> opcmd)</span> </span>&#123;</div><div class="line">    fragment.mFragmentManager = mManager;</div><div class="line">    ...</div><div class="line">    Op op = <span class="keyword">new</span> Op();</div><div class="line">    op.cmd = opcmd; <span class="comment">//这里的opcmd为OP_REPLACE</span></div><div class="line">    op.fragment = fragment;</div><div class="line">    addOp(op);</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="comment">//Op为一个链表结构，主要用来记录Fragment的使用链</span></div><div class="line"><span class="function"><span class="keyword">void</span> <span class="title">addOp</span><span class="params">(Op op)</span> </span>&#123;</div><div class="line">    <span class="keyword">if</span> (mHead == <span class="keyword">null</span>) &#123;</div><div class="line">        mHead = mTail = op;</div><div class="line">    &#125; <span class="keyword">else</span> &#123;</div><div class="line">        op.prev = mTail;</div><div class="line">        mTail.next = op;</div><div class="line">        mTail = op;</div><div class="line">    &#125;</div><div class="line">    op.enterAnim = mEnterAnim;</div><div class="line">    op.exitAnim = mExitAnim;</div><div class="line">    op.popEnterAnim = mPopEnterAnim;</div><div class="line">    op.popExitAnim = mPopExitAnim;</div><div class="line">    mNumOp++;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>那么到现在为止，好像并没有什么实质的变化，Activity依然是个空的Activity，Fragment依然是个没有展示的Fragment。那么重量级的方法来了commit()方法。这个方法对有些刚刚使用Fragment的开发者来说容易忘记的方法。常常写完发现并没有什么XX用。我看看到commit()依然是BackStackRecord的方法.</p>
<figure class="highlight aspectj"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//allowStateLoss=false</span></div><div class="line"><span class="comment">//mAddToBackStack默认为false</span></div><div class="line"><span class="function"><span class="keyword">int</span> <span class="title">commitInternal</span><span class="params">(<span class="keyword">boolean</span> allowStateLoss)</span> </span>&#123;</div><div class="line">    <span class="keyword">if</span> (mCommitted) <span class="keyword">throw</span> <span class="keyword">new</span> IllegalStateException(<span class="string">"commit already called"</span>);</div><div class="line">    <span class="keyword">if</span> (FragmentManagerImpl.DEBUG) &#123;</div><div class="line">        Log.v(TAG, <span class="string">"Commit: "</span> + <span class="keyword">this</span>);</div><div class="line">        LogWriter logw = <span class="keyword">new</span> LogWriter(TAG);</div><div class="line">        PrintWriter pw = <span class="keyword">new</span> PrintWriter(logw);</div><div class="line">        dump(<span class="string">"  "</span>, <span class="keyword">null</span>, pw, <span class="keyword">null</span>);</div><div class="line">    &#125;</div><div class="line">    mCommitted = <span class="keyword">true</span>;</div><div class="line">    <span class="keyword">if</span> (mAddToBackStack) &#123;</div><div class="line">        mIndex = mManager.allocBackStackIndex(<span class="keyword">this</span>);</div><div class="line">    &#125; <span class="keyword">else</span> &#123;</div><div class="line">        mIndex = <span class="number">-1</span>;</div><div class="line">    &#125;</div><div class="line">    mManager.enqueueAction(<span class="keyword">this</span>, allowStateLoss);<span class="comment">//mManager为FragmentManagerImpl</span></div><div class="line">    <span class="keyword">return</span> mIndex;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>我们来看FragmentManagerImpl的enqueueAction方法:<br>//action 为BackStackRecord对象<br>public void enqueueAction(Runnable action, boolean allowStateLoss) {<br>if (!allowStateLoss) {<br>checkStateLoss();<br>}<br>synchronized (this) {<br>if (mDestroyed || mHost == null) {<br>throw new IllegalStateException(“Activity has been destroyed”);<br>}<br>if (mPendingActions == null) {<br>mPendingActions = new ArrayList<runnable>();<br>}<br>mPendingActions.add(action);<br>if (mPendingActions.size() == 1) {<br>mHost.getHandler().removeCallbacks(mExecCommit);<br>mHost.getHandler().post(mExecCommit);<br>}<br>}<br>}<br>这段代码主要是去执行传进来的Runable的run方法。</runnable></p>
<figure class="highlight nix"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div></pre></td><td class="code"><pre><div class="line">public void run() &#123;</div><div class="line">   ...</div><div class="line">    Op <span class="attr">op</span> = mHead;</div><div class="line">    while (op != <span class="literal">null</span>) &#123;</div><div class="line">        ...</div><div class="line">            case OP_REPLACE: &#123;</div><div class="line">                Fragment <span class="attr">f</span> = op.fragment;</div><div class="line">                int <span class="attr">containerId</span> = f.mContainerId;</div><div class="line">                <span class="keyword">if</span> (mManager.mAdded != <span class="literal">null</span>) &#123;</div><div class="line">                    for (int <span class="attr">i</span> = mManager.mAdded.size() - <span class="number">1</span>; i &gt;= <span class="number">0</span>; i--) &#123;</div><div class="line">                        Fragment <span class="attr">old</span> = mManager.mAdded.get(i);</div><div class="line">                        <span class="keyword">if</span> (FragmentManagerImpl.DEBUG) Log.v(TAG,</div><div class="line">                                <span class="string">"OP_REPLACE: adding="</span> + f + <span class="string">" old="</span> + old);</div><div class="line">                        <span class="keyword">if</span> (old.<span class="attr">mContainerId</span> == containerId) &#123;</div><div class="line">                            <span class="keyword">if</span> (<span class="attr">old</span> == f) &#123;</div><div class="line">                                op.<span class="attr">fragment</span> = <span class="attr">f</span> = <span class="literal">null</span>;</div><div class="line">                            &#125; <span class="keyword">else</span> &#123;</div><div class="line">                                <span class="keyword">if</span> (op.<span class="attr">removed</span> == <span class="literal">null</span>) &#123;</div><div class="line">                                    op.<span class="attr">removed</span> = new ArrayList&lt;Fragment&gt;();</div><div class="line">                                &#125;</div><div class="line">                                op.removed.add(old);</div><div class="line">                                old.<span class="attr">mNextAnim</span> = exitAnim;</div><div class="line">                                <span class="keyword">if</span> (mAddToBackStack) &#123;</div><div class="line">                                    old.mBackStackNesting += <span class="number">1</span>;</div><div class="line">                                    <span class="keyword">if</span> (FragmentManagerImpl.DEBUG) Log.v(TAG, <span class="string">"Bump nesting of "</span></div><div class="line">                                            + old + <span class="string">" to "</span> + old.mBackStackNesting);</div><div class="line">                                &#125;</div><div class="line">                                mManager.removeFragment(old, transition, transitionStyle);</div><div class="line">                            &#125;</div><div class="line">                        &#125;</div><div class="line">                    &#125;</div><div class="line">                &#125;</div><div class="line">                <span class="keyword">if</span> (f != <span class="literal">null</span>) &#123;</div><div class="line">                    f.<span class="attr">mNextAnim</span> = enterAnim;</div><div class="line">                    mManager.addFragment(f, <span class="literal">false</span>);</div><div class="line">                &#125;</div><div class="line">            &#125; break;</div><div class="line">            ...</div><div class="line">            mManager.moveToState(mManager.mCurState, transition, transitionStyle, <span class="literal">true</span>);</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>这段代码很长，但是我们只关心OP_REPLACE的操作符。我们看到上面的代码主要是通过操作FragmentManagerImpl来remove老的Fragment，add新的Fragment。好的，我们把重点给到addFragment这个方法。</p>
<figure class="highlight kotlin"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> void addFragment(Fragment fragment, boolean moveToStateNow) &#123;</div><div class="line">    <span class="keyword">if</span>(<span class="keyword">this</span>.mAdded == <span class="literal">null</span>) &#123;</div><div class="line">        <span class="keyword">this</span>.mAdded = new ArrayList();</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="keyword">if</span>(DEBUG) &#123;</div><div class="line">        Log.v(<span class="string">"FragmentManager"</span>, <span class="string">"add: "</span> + fragment);</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="keyword">this</span>.makeActive(fragment); <span class="comment">// 将Fragment放入mActive集合中待显示</span></div><div class="line">    <span class="keyword">if</span>(!fragment.mDetached) &#123;</div><div class="line">        <span class="keyword">if</span>(<span class="keyword">this</span>.mAdded.contains(fragment)) &#123;</div><div class="line">            <span class="keyword">throw</span> new IllegalStateException(<span class="string">"Fragment already added: "</span> + fragment);</div><div class="line">        &#125;</div><div class="line"></div><div class="line">        <span class="keyword">this</span>.mAdded.add(fragment);</div><div class="line">        fragment.mAdded = <span class="literal">true</span>;</div><div class="line">        fragment.mRemoving = <span class="literal">false</span>;</div><div class="line">        <span class="keyword">if</span>(fragment.mHasMenu &amp;&amp; fragment.mMenuVisible) &#123;</div><div class="line">            <span class="keyword">this</span>.mNeedMenuInvalidate = <span class="literal">true</span>;</div><div class="line">        &#125;</div><div class="line"></div><div class="line">        moveToStateNow == <span class="literal">false</span></div><div class="line">        <span class="keyword">if</span>(moveToStateNow) &#123;</div><div class="line">            <span class="keyword">this</span>.moveToState(fragment);</div><div class="line">        &#125;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>这里最关键的代码是makeActive(fragment)。我们在回到BackStackRecord的run方法中，走过一系列的case后走到最后的方法moveToState。</p>
<figure class="highlight haxe"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div></pre></td><td class="code"><pre><div class="line">void moveToState(int <span class="keyword">new</span><span class="type">State</span>, int transit, int transitStyle, boolean always) &#123;</div><div class="line">    <span class="keyword">if</span>(<span class="built_in">this</span>.mHost == <span class="literal">null</span> &amp;&amp; <span class="keyword">new</span><span class="type">State</span> != <span class="number">0</span>) &#123;</div><div class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="type">IllegalStateException</span>(<span class="string">"No host"</span>);</div><div class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span>(always || <span class="built_in">this</span>.mCurState != <span class="keyword">new</span><span class="type">State</span>) &#123;</div><div class="line">       ...</div><div class="line">            <span class="keyword">for</span>(int i = <span class="number">0</span>; i &lt; <span class="built_in">this</span>.mActive.size(); ++i) &#123;</div><div class="line">                Fragment f = (Fragment)<span class="built_in">this</span>.mActive.<span class="keyword">get</span>(i);</div><div class="line">                <span class="keyword">if</span>(f != <span class="literal">null</span>) &#123;</div><div class="line">                    <span class="built_in">this</span>.moveToState(f, <span class="keyword">new</span><span class="type">State</span>, transit, transitStyle, <span class="literal">false</span>);</div><div class="line">                    <span class="keyword">if</span>(f.mLoaderManager != <span class="literal">null</span>) &#123;</div><div class="line">                        loadersRunning |= f.mLoaderManager.hasRunningLoaders();</div><div class="line">                    &#125;</div><div class="line">                &#125;</div><div class="line">            &#125;</div><div class="line">       ...</div><div class="line">        &#125;</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>这个方法是在mActive中取出刚刚放入的Fragment。最后调用moveToState（Fragment…）方法</p>
<figure class="highlight groovy"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">void</span> moveToState(Fragment f, <span class="keyword">int</span> newState, <span class="keyword">int</span> transit, <span class="keyword">int</span> transitionStyle,</div><div class="line">        <span class="keyword">boolean</span> keepActive) &#123;</div><div class="line">    <span class="comment">//...</span></div><div class="line">    <span class="keyword">if</span> (f.mState &lt; newState) &#123;</div><div class="line">        <span class="comment">//...</span></div><div class="line">        <span class="keyword">switch</span> (f.mState) &#123;</div><div class="line">            <span class="keyword">case</span> Fragment.<span class="string">INITIALIZING:</span></div><div class="line">                <span class="comment">//...</span></div><div class="line">                f.mHost = mHost;</div><div class="line">                f.mParentFragment = mParent;</div><div class="line">                f.mFragmentManager = mParent != <span class="literal">null</span></div><div class="line">                        ? mParent.mChildFragmentManager : mHost.getFragmentManagerImpl();</div><div class="line">                f.mCalled = <span class="literal">false</span>;</div><div class="line">                f.onAttach(mHost.getContext());</div><div class="line">                <span class="comment">//...</span></div><div class="line">                <span class="keyword">if</span> (f.mParentFragment == <span class="literal">null</span>) &#123;</div><div class="line">                    mHost.onAttachFragment(f);</div><div class="line">                &#125;</div><div class="line"></div><div class="line">                <span class="keyword">if</span> (!f.mRetaining) &#123;</div><div class="line">                    f.performCreate(f.mSavedFragmentState);</div><div class="line">                &#125;</div><div class="line">                f.mRetaining = <span class="literal">false</span>;</div><div class="line">                <span class="keyword">if</span> (f.mFromLayout) &#123;</div><div class="line">                    <span class="comment">//...</span></div><div class="line">                &#125;</div><div class="line">            <span class="comment">//...</span></div><div class="line">    &#125;</div><div class="line"></div><div class="line">    f.mState = newState;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>当Fragment走到了现在，我们终于看到了mHost的赋值，同时给Fragment的创建流程也有了一定的了解了。也就是说Fragment在Attach到宿主Activity是mHost进行赋值。那么我们又回到上面说的Bug上，这里mHost运行了一段时间后，突然为空了。这让我们联想到是由于宿主Activity和Fragment失去的连接，导致了Fragment的mHost为Null。那么在开发的时候不是必现的，那么排除了这种情况是代码上的问题。还有没有其他的Activity于Fragment失联的情况了，猜想是App处在后台时，在系统内存紧张后回收掉了Activity，但是同时Fragment在做耗时操作刚好又用到了getActivity().那么悲剧就这样产生了。</p>
<p>我们来看下Activity在销毁是的代码。</p>
<figure class="highlight aspectj"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">final</span> <span class="function"><span class="keyword">void</span> <span class="title">performDestroy</span><span class="params">()</span> </span>&#123;</div><div class="line">    mDestroyed = <span class="keyword">true</span>;</div><div class="line">    mWindow.destroy();</div><div class="line">    mFragments.dispatchDestroy();</div><div class="line">    onDestroy();</div><div class="line">    mFragments.doLoaderDestroy();</div><div class="line">    <span class="keyword">if</span> (mVoiceInteractor != <span class="keyword">null</span>) &#123;</div><div class="line">        mVoiceInteractor.detachActivity();</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>我们看到了mFragments.dispatchDestroy()方法。</p>
<figure class="highlight lasso"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div></pre></td><td class="code"><pre><div class="line">    <span class="keyword">public</span> <span class="literal">void</span> dispatchDestroy() &#123;</div><div class="line">        mDestroyed = <span class="literal">true</span>;</div><div class="line">        execPendingActions();</div><div class="line">        moveToState(Fragment.INITIALIZING, <span class="literal">false</span>);</div><div class="line">        mHost = <span class="built_in">null</span>;</div><div class="line">        mContainer = <span class="built_in">null</span>;</div><div class="line">        mParent = <span class="built_in">null</span>;</div><div class="line">    &#125;</div><div class="line"></div><div class="line"><span class="literal">void</span> moveToState(Fragment f, int newState, int transit, int transitionStyle,</div><div class="line">        <span class="built_in">boolean</span> keepActive) &#123;</div><div class="line">    <span class="keyword">if</span> (f.mState &lt; newState) &#123;</div><div class="line">        <span class="params">...</span></div><div class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (f.mState &gt; newState) &#123;</div><div class="line">        switch (f.mState) &#123;</div><div class="line">            <span class="params">...</span></div><div class="line">            <span class="keyword">case</span> Fragment.CREATED:</div><div class="line">                <span class="keyword">if</span> (newState &lt; Fragment.CREATED) &#123;</div><div class="line">                    <span class="keyword">if</span> (mDestroyed) &#123;</div><div class="line">                        <span class="params">...</span></div><div class="line">                    &#125;</div><div class="line">                    <span class="keyword">if</span> (f.mAnimatingAway != <span class="built_in">null</span>) &#123;</div><div class="line">                        <span class="params">...</span></div><div class="line">                    &#125; <span class="keyword">else</span> &#123;</div><div class="line">                        <span class="keyword">if</span> (DEBUG) <span class="keyword">Log</span>.v(<span class="built_in">TAG</span>, <span class="string">"movefrom CREATED: "</span> + f);</div><div class="line">                        <span class="keyword">if</span> (!f.mRetaining) &#123;</div><div class="line">                            f.performDestroy();</div><div class="line">                        &#125; <span class="keyword">else</span> &#123;</div><div class="line">                            f.mState = Fragment.INITIALIZING;</div><div class="line">                        &#125;</div><div class="line"></div><div class="line">                        f.performDetach();</div><div class="line">                        <span class="keyword">if</span> (!keepActive) &#123;</div><div class="line">                            <span class="keyword">if</span> (!f.mRetaining) &#123;</div><div class="line">                                makeInactive(f);</div><div class="line">                            &#125; <span class="keyword">else</span> &#123;</div><div class="line">                                f.mHost = <span class="built_in">null</span>;</div><div class="line">                                f.mParentFragment = <span class="built_in">null</span>;</div><div class="line">                                f.mFragmentManager = <span class="built_in">null</span>;</div><div class="line">                            &#125;</div><div class="line">                        &#125;</div><div class="line">                    &#125;</div><div class="line">                &#125;</div><div class="line">        &#125;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">  <span class="params">...</span></div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>最后会走到else分支中,将Fragment的mHost置空，这就导致了getActivity()NPE的出现。<br>对于这类问题是因为没有控制好Fragment于Activity失联后没有正确的取消耗时的操作，那么需要开发者在onDetach的时候及时取消掉耗时的操作。</p>
<h2 id="Fragment之replace和add的区别"><a href="#Fragment之replace和add的区别" class="headerlink" title="Fragment之replace和add的区别"></a><a href="#Fragment_u4E4Breplace_u548Cadd_u7684_u533A_u522B" title="Fragment之replace和add的区别"></a>Fragment之replace和add的区别</h2><p>Fragment的replace和add在一般情况下展现的效果是一致的,不经历一些Bug 可能用replace的人一直用replace，用add的人一直用add，那么这个Bug究竟是什么呢。其实也是在特殊时期发生的事，那就是在Activity回收后恢复时,出现了多个Fragment,当然这个Bug官方在v4-24.0.0+ 开始已经解决了，后续将不会出现这个问题。这个Bug主要产生点就是Activity销毁和恢复是状态保存机制造成的。系统在回收Activity的时候会保存Fragment的状态。</p>
<figure class="highlight processing"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">final</span> <span class="keyword">String</span> mClassName;</div><div class="line"><span class="keyword">final</span> <span class="built_in">int</span> mIndex;</div><div class="line"><span class="keyword">final</span> <span class="built_in">boolean</span> mFromLayout;</div><div class="line"><span class="keyword">final</span> <span class="built_in">int</span> mFragmentId;</div><div class="line"><span class="keyword">final</span> <span class="built_in">int</span> mContainerId;</div><div class="line"><span class="keyword">final</span> <span class="keyword">String</span> mTag;</div><div class="line"><span class="keyword">final</span> <span class="built_in">boolean</span> mRetainInstance;</div><div class="line"><span class="keyword">final</span> <span class="built_in">boolean</span> mDetached;</div><div class="line"><span class="keyword">final</span> Bundle mArguments;</div></pre></td></tr></table></figure>
<p>24.0.0之前保存的变量如上。但是在使用addAPI是经常需要使用Hide和Show的操作，这些操作都是根据mHidden变量来控制的，在来看下以前的版本，压根就没有保存这个变量，所以在使用add去操作Fragment时会将add的多个Fragment同时显示出来，或者在onCreate里再次创建了同一个Fragment，Fragment默认的mHidden = false，这样就会造成重影的问题。在24.0.0之后，官方加入了mHidden字段。来保存Fragment显隐问题。</p>
<p>那么replace为啥没有这样的问题出现呢，而add的操作就会存在。我们来看下源码。</p>
<figure class="highlight processing"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> FragmentTransaction <span class="built_in">add</span>(Fragment fragment, <span class="keyword">String</span> tag) &#123;</div><div class="line">    doAddOp(<span class="number">0</span>, fragment, tag, OP_ADD);</div><div class="line">    <span class="keyword">return</span> <span class="keyword">this</span>;</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="keyword">public</span> FragmentTransaction replace(<span class="built_in">int</span> containerViewId, Fragment fragment, <span class="keyword">String</span> tag) &#123;</div><div class="line">    <span class="keyword">if</span> (containerViewId == <span class="number">0</span>) &#123;</div><div class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException(<span class="string">"Must use non-zero containerViewId"</span>);</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    doAddOp(containerViewId, fragment, tag, OP_REPLACE);</div><div class="line">    <span class="keyword">return</span> <span class="keyword">this</span>;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>add和replace的不同点只是在构造Op是的cmd不一样，一个是OP_ADD，一个OP_REPLACE。</p>
<figure class="highlight groovy"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="keyword">void</span> run() &#123;</div><div class="line">        ...</div><div class="line">        <span class="keyword">while</span> (op != <span class="literal">null</span>) &#123;</div><div class="line">            <span class="keyword">int</span> enterAnim = state != <span class="literal">null</span> ? 0 : op.enterAnim;</div><div class="line">            <span class="keyword">int</span> exitAnim = state != <span class="literal">null</span> ? 0 : op.exitAnim;</div><div class="line">            <span class="keyword">switch</span> (op.cmd) &#123;</div><div class="line">                <span class="keyword">case</span> <span class="string">OP_ADD:</span> &#123;</div><div class="line">                    Fragment f = op.fragment;</div><div class="line">                    f.mNextAnim = enterAnim;</div><div class="line">                    mManager.addFragment(f, <span class="literal">false</span>);</div><div class="line">                &#125; <span class="keyword">break</span>;</div><div class="line">                <span class="keyword">case</span> <span class="string">OP_REPLACE:</span> &#123;</div><div class="line">                    Fragment f = op.fragment;</div><div class="line">                    <span class="keyword">int</span> containerId = f.mContainerId;</div><div class="line">                    <span class="keyword">if</span> (mManager.mAdded != <span class="literal">null</span>) &#123;</div><div class="line">                        <span class="keyword">for</span> (<span class="keyword">int</span> i = mManager.mAdded.size() - <span class="number">1</span>; i &gt;= <span class="number">0</span>; i--) &#123;</div><div class="line">                            Fragment old = mManager.mAdded.get(i);</div><div class="line">                            <span class="keyword">if</span> (FragmentManagerImpl.DEBUG) Log.v(TAG,</div><div class="line">                                    <span class="string">"OP_REPLACE: adding="</span> + f + <span class="string">" old="</span> + old);</div><div class="line">                            <span class="keyword">if</span> (old.mContainerId == containerId) &#123;</div><div class="line">                                <span class="keyword">if</span> (old == f) &#123;</div><div class="line">                                    op.fragment = f = <span class="literal">null</span>;</div><div class="line">                                &#125; <span class="keyword">else</span> &#123;</div><div class="line">                                    <span class="keyword">if</span> (op.removed == <span class="literal">null</span>) &#123;</div><div class="line">                                        op.removed = <span class="keyword">new</span> ArrayList&lt;Fragment&gt;();</div><div class="line">                                    &#125;</div><div class="line">                                    op.removed.add(old);</div><div class="line">                                    old.mNextAnim = exitAnim;</div><div class="line">                                    <span class="keyword">if</span> (mAddToBackStack) &#123;</div><div class="line">                                        old.mBackStackNesting += <span class="number">1</span>;</div><div class="line">                                        <span class="keyword">if</span> (FragmentManagerImpl.DEBUG) Log.v(TAG, <span class="string">"Bump nesting of "</span></div><div class="line">                                                + old + <span class="string">" to "</span> + old.mBackStackNesting);</div><div class="line">                                    &#125;</div><div class="line">                                    mManager.removeFragment(old, transition, transitionStyle);</div><div class="line">                                &#125;</div><div class="line">                            &#125;</div><div class="line">                        &#125;</div><div class="line">                    &#125;</div><div class="line">                    <span class="keyword">if</span> (f != <span class="literal">null</span>) &#123;</div><div class="line">                        f.mNextAnim = enterAnim;</div><div class="line">                        mManager.addFragment(f, <span class="literal">false</span>);</div><div class="line">                    &#125;</div><div class="line">                &#125; <span class="keyword">break</span>;</div><div class="line">               ...</div><div class="line"></div><div class="line">        mManager.moveToState(mManager.mCurState, transition, transitionStyle, <span class="literal">true</span>);</div><div class="line"></div><div class="line">        ...</div><div class="line">    &#125;</div></pre></td></tr></table></figure>
<p>这里分别对cmd的操作可以看出来add是直接添加一个Fragment，可以多个Fragment一起存在，而replace则是先remove其他Fragment在add新的Fragment。这两个API使用场景就发生了变化。<br>对于在一个Fragment只存在一个或者存在多个不易切换的Fragment适合使用replace，毕竟replace不需要耗费其他的内存来保存多个Fragment。在使用多个Fragment频繁切换时更适合add，Fragment的切换使用Hide和show来实现，这样数据不需要再次加载，即是一种空间换速度的方式，这里也可以看出来replace的时候是remove了其他的Fragment所以一般不会产生多个Fragment的同时展现。</p>

            <div class="post-copyright">
    <div class="content">
        <p>最后更新： 2017年09月15日 15:00</p>
        <p>原始链接： <a class="post-url" href="/2017/04/26/Fragment弃坑之旅/" title="Fragment弃坑之旅">http://mjjde.github.io/2017/04/26/Fragment弃坑之旅/</a></p>
        <footer>
            <a href="http://mjjde.github.io">
                <img src="/images/avatar.jpg" alt="Joker Mei">
                Joker Mei
            </a>
        </footer>
    </div>
</div>

      
    </div>
    <footer class="article-footer">
        
        
<div class="post-share">
    <a href="javascript:;" id="share-sub" class="post-share-fab">
        <i class="fa fa-share-alt"></i>
    </a>
    <div class="post-share-list" id="share-list">
        <ul class="share-icons">
          <li>
            <a class="weibo share-sns" target="_blank" href="http://service.weibo.com/share/share.php?url=http://mjjde.github.io/2017/04/26/Fragment弃坑之旅/&title=《Fragment弃坑之旅》 — 清风向阳&pic=http://mjjde.github.ioimages/avatar.jpg" data-title="微博">
              <i class="fa fa-weibo"></i>
            </a>
          </li>
          <li>
            <a class="weixin share-sns" id="wxFab" href="javascript:;" data-title="微信">
              <i class="fa fa-weixin"></i>
            </a>
          </li>
          <li>
            <a class="qq share-sns" target="_blank" href="http://connect.qq.com/widget/shareqq/index.html?url=http://mjjde.github.io/2017/04/26/Fragment弃坑之旅/&title=《Fragment弃坑之旅》 — 清风向阳&source=
Fragment至诞生之日起，就开始饱受争议，很多人都认为Fragment的设计不合理，并提倡放弃Fragment，这种现象产生的原因我觉得大概就是使用..." data-title="QQ">
              <i class="fa fa-qq"></i>
            </a>
          </li>
          <li>
            <a class="facebook share-sns" target="_blank" href="https://www.facebook.com/sharer/sharer.php?u=http://mjjde.github.io/2017/04/26/Fragment弃坑之旅/" data-title="Facebook">
              <i class="fa fa-facebook"></i>
            </a>
          </li>
          <li>
            <a class="twitter share-sns" target="_blank" href="https://twitter.com/intent/tweet?text=《Fragment弃坑之旅》 — 清风向阳&url=http://mjjde.github.io/2017/04/26/Fragment弃坑之旅/&via=http://mjjde.github.io" data-title="Twitter">
              <i class="fa fa-twitter"></i>
            </a>
          </li>
          <li>
            <a class="google share-sns" target="_blank" href="https://plus.google.com/share?url=http://mjjde.github.io/2017/04/26/Fragment弃坑之旅/" data-title="Google+">
              <i class="fa fa-google-plus"></i>
            </a>
          </li>
        </ul>
     </div>
</div>
<div class="post-modal wx-share" id="wxShare">
    <a class="close" href="javascript:;" id="wxShare-close">×</a>
    <p>扫一扫，分享到微信</p>
    <img src="//api.qrserver.com/v1/create-qr-code/?data=http://mjjde.github.io/2017/04/26/Fragment弃坑之旅/" alt="微信分享二维码">
</div>

<div class="mask"></div>

        
        <ul class="article-footer-menu">
            
            
  <li class="article-footer-tags">
    <i class="fa fa-tags"></i>
      
    <a href="/tags/Fragment/" class="color4">Fragment</a>
      
    <a href="/tags/android/" class="color3">android</a>
      
  </li>

        </ul>
        
    </footer>
  </div>
</article>


    <aside class="post-toc-pos post-toc-top" id="post-toc">
        <nav class="post-toc-wrap">
            <ol class="post-toc"><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#getActivity-方法报NPE"><span class="post-toc-text">getActivity()方法报NPE</span></a></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#Fragment之replace和add的区别"><span class="post-toc-text">Fragment之replace和add的区别</span></a></li></ol>
        </nav>
    </aside>
    

<nav id="article-nav">
  
    <a href="/2017/04/26/Android-Binder技术ServiceManager之服务注册请求的发送/" id="article-nav-newer" class="article-nav-link-wrap">

      <span class="article-nav-title">
        <i class="fa fa-hand-o-left" aria-hidden="true"></i>
        
          Android-Binder技术ServiceManager之服务注册请求的发送
        
      </span>
    </a>
  
  
    <a href="/2017/04/25/Android-Binder技术之ServiceManager启动/" id="article-nav-older" class="article-nav-link-wrap">
      <span class="article-nav-title">Android-Binder技术之ServiceManager启动</span>
      <i class="fa fa-hand-o-right" aria-hidden="true"></i>
    </a>
  
</nav>



    
</section>
        
      </div>
      <footer id="footer">
  <div class="outer">
    <div id="footer-info" class="inner">
      
<p>
    <span id="busuanzi_container_site_uv" style='display:none'>
        总访客数：<span id="busuanzi_value_site_uv"></span>
    </span>
    <span id="busuanzi_container_site_pv" style='display:none'>
        总访问量：<span id="busuanzi_value_site_pv"></span>
    </span>
</p>


      <p>
        Powered by  <a href="http://hexo.io/" target="_blank">Hexo</a>
        Theme <a href="//github.com/wongminho/hexo-theme-miho" target="_blank">MiHo</a>
      &copy; 2018 Joker Mei<br>
      </p>
    </div>
  </div>
</footer>
    <script async src="//dn-lbstatics.qbox.me/busuanzi/2.3/busuanzi.pure.mini.js"></script>
<script src="//cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
<script>
  var mihoConfig = {
      root: "http://mjjde.github.io",
      animate: false,
      isHome: false,
      share: true
  }
</script>
<div class="sidebar">
    <!-- <div id="sidebar-search" title="Search">
        <i class="fa fa-search"></i>
    </div> -->
    <div id="sidebar-category" title="Categories">
        <i class="fa fa-book"></i>
    </div>
    <div id="sidebar-tag" title="Tags">
        <i class="fa fa-tags"></i>
    </div>
    <div id="sidebar-top">
        <span class="sidebar-top-icon"><i class="fa fa-angle-up"></i></span>
    </div>
</div>
<div class="sidebar-menu-box" id="sidebar-menu-box">
    <div class="sidebar-menu-box-container">
        <div id="sidebar-menu-box-categories">
            <a class="category-link" href="/categories/Android技术/">Android技术</a><a class="category-link" href="/categories/其他技术/">其他技术</a><a class="category-link" href="/categories/网络技术/">网络技术</a><a class="category-link" href="/categories/设计模式/">设计模式</a>
        </div>
        <div id="sidebar-menu-box-tags">
            <a href="/tags/Activity/" style="font-size: 10px;">Activity</a> <a href="/tags/Android/" style="font-size: 16px;">Android</a> <a href="/tags/Android-IPC/" style="font-size: 10px;">Android-IPC</a> <a href="/tags/Binder/" style="font-size: 16px;">Binder</a> <a href="/tags/DiskLruCache/" style="font-size: 10px;">DiskLruCache</a> <a href="/tags/Fragment/" style="font-size: 10px;">Fragment</a> <a href="/tags/HTTP/" style="font-size: 20px;">HTTP</a> <a href="/tags/Java/" style="font-size: 10px;">Java</a> <a href="/tags/Notification/" style="font-size: 10px;">Notification</a> <a href="/tags/RemoteView/" style="font-size: 10px;">RemoteView</a> <a href="/tags/Rxjava/" style="font-size: 14px;">Rxjava</a> <a href="/tags/ServiceManager/" style="font-size: 14px;">ServiceManager</a> <a href="/tags/android/" style="font-size: 12px;">android</a> <a href="/tags/gradle/" style="font-size: 10px;">gradle</a> <a href="/tags/java/" style="font-size: 18px;">java</a> <a href="/tags/other/" style="font-size: 10px;">other</a> <a href="/tags/volley/" style="font-size: 12px;">volley</a> <a href="/tags/widget/" style="font-size: 10px;">widget</a> <a href="/tags/事件/" style="font-size: 10px;">事件</a> <a href="/tags/组件化/" style="font-size: 10px;">组件化</a> <a href="/tags/设计模式/" style="font-size: 18px;">设计模式</a>
        </div>
    </div>
    <a href="javascript:;" class="sidebar-menu-box-close">&times;</a>
</div>
<div class="mobile-header-menu-nav" id="mobile-header-menu-nav">
    <div id="mobile-header-menu-container">
        <span class="title">Menu</span>
        <ul class="mobile-header-menu-navbar">
            
            <li>
                <a  href="/">
                    <i class="fa fa-home"></i><span>Home</span>
                </a>
            </li>
            
            <li>
                <a  href="/archives">
                    <i class="fa fa-archive"></i><span>Archives</span>
                </a>
            </li>
            
            <li>
                <a  href="/about">
                    <i class="fa fa-user"></i><span>About</span>
                </a>
            </li>
            
        </ul>
    </div>
</div>
<div class="search-wrap">
    <span class="search-close">&times;</span>
        <a href="javascript:;" class="header-icon waves-effect waves-circle waves-light" id="back">
            <i class="icon icon-lg icon-chevron-left"></i>
        </a>
        <input class="search-field" placeholder="Search..." id="keywords">
        <a id="search-submit" href="javascript:;">
            <i class="fa fa-search"></i>
        </a>
    <div class="search-container" id="search-container">
        <ul class="search-result" id="search-result">
        </ul>
    </div>
</div>

<div id="search-tpl">
    <li class="search-result-item">
        <a href="{url}" class="search-item-li">
            <span class="search-item-li-title" title="{title}">{title}</span>
        </a>
    </li>
</div>
<script src="/js/search.js"></script>
<script src="/js/main.js"></script>








  </div>
</body>
</html>